//
//  VideoPlayerViewController.m
//  18Birdies
//
//  Created by Lc on 15/8/2.
//  Copyright (c) 2015年 Lc. All rights reserved.
//

#import <MediaPlayer/MediaPlayer.h>

#import "LcFoundation.h"
#import "VideoPlayerViewController.h"
#import <AVKit/AVKit.h>
#import "VideoProgressSlider.h"
#import "LcVideoPlayer.h"

@interface VideoPlayerViewController () <VideoProgressSliderDelegate>

@property(nonatomic, weak) IBOutlet UIView* videoContainerView;
@property(nonatomic, weak) IBOutlet UIButton* closeButton;
@property(nonatomic, weak) IBOutlet UIView* bottomControlBar;
@property(nonatomic, weak) IBOutlet UIButton* playButton;
@property(nonatomic, weak) IBOutlet UIButton* voiceButton;
@property(nonatomic, weak) IBOutlet UIButton* rotatoButton;
@property(nonatomic, weak) IBOutlet NSLayoutConstraint* playerBottomActionContainerConstraint;
@property(nonatomic, weak) IBOutlet VideoProgressSlider* progressSlider;
@property(nonatomic, weak) IBOutlet UILabel* totalTimeLabel;
@property(nonatomic, weak) IBOutlet UILabel* currentTimeLabel;
@property(nonatomic, weak) IBOutlet NSLayoutConstraint* bottomBarBottomConstraint;
@property(nonatomic, weak) IBOutlet NSLayoutConstraint* closeBtnBottomConstraint;

@property(nonatomic, assign) BOOL isPreviewEndPlay;

@property(nonatomic, assign) BOOL fromIsHidingNavBar;

@property(nonatomic, assign, readonly) BOOL isUIPlaying;

@property(nonatomic, strong) LcVideoPlayer* videoPlayer;
@property(nonatomic, assign) BOOL videoPlayerCreatedOutside;
@property(nonatomic, assign) CGRect originFrame;

@end

@implementation VideoPlayerViewController

+ (instancetype)playWithVideoUrl:(NSURL*)videoUrl
              fromViewController:(BaseViewController*)fromViewController {
  VideoPlayerViewController* viewController =
      [[VideoPlayerViewController alloc] initWithDeletableVideoUrl:videoUrl
                                                fromViewController:fromViewController];
  [self videoController:viewController pushFromViewController:fromViewController];
  return viewController;
}

+ (void)videoController:(VideoPlayerViewController*)videoController
    pushFromViewController:(BaseViewController*)fromViewController {
  if (fromViewController.navigationController == nil) {
    NSLog(@"Must have a navigation to push this");
    LC_FAIL();
  }
  [fromViewController.navigationController.view.layer addAnimation:self.pushAnimateTransition
                                                            forKey:nil];
  [fromViewController.navigationController pushViewController:videoController animated:NO];
}

+ (instancetype)playWithVideoPlayer:(LcVideoPlayer*)player
                 fromViewController:(BaseViewController*)fromViewController {
  VideoPlayerViewController* viewController =
      [[VideoPlayerViewController alloc] initWithVideoPlayer:player
                                          fromViewController:fromViewController];
  [self videoController:viewController pushFromViewController:fromViewController];
  return viewController;
}

+ (instancetype)playWithAVAsset:(AVAsset*)avasset
             fromViewController:(BaseViewController*)fromViewController {
  LC_CHECK_NOT_NULL(avasset);
  LC_CHECK_NOT_NULL(fromViewController);
  VideoPlayerViewController* viewController =
      [[VideoPlayerViewController alloc] initWithAVAsset:avasset
                                      fromViewController:fromViewController];
  [self videoController:viewController pushFromViewController:fromViewController];
  return viewController;
}

+ (CATransition*)pushAnimateTransition {
  CATransition* transition = [CATransition animation];
  transition.duration = 0.25;
  transition.timingFunction =
      [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
  transition.type = kCATransitionFade;
  return transition;
}

- (BOOL)isUIPlaying {
  return !self.playButton.selected;
}

- (instancetype)initWithDeletableVideoUrl:(NSURL*)videoUrl
                       fromViewController:(BaseViewController*)fromViewController {
  LC_CHECK_NOT_NULL(videoUrl);
  LC_CHECK_NOT_NULL(fromViewController);
  if (self = [super init]) {
    _videoUrl = videoUrl;
    self.fromViewController = fromViewController;
  }
  return self;
}

- (instancetype)initWithVideoPlayer:(LcVideoPlayer*)player
                 fromViewController:(BaseViewController*)fromViewController {
  LC_CHECK_NOT_NULL(player);
  LC_CHECK_NOT_NULL(fromViewController);
  if (self = [super init]) {
    self->_videoPlayer = player;
    CGRect frame = [player.screen convertRect:player.screen.bounds
                                       toView:[[UIApplication sharedApplication] keyWindow]];
    self->_originFrame = frame;
    self.videoPlayerCreatedOutside = YES;
    self.fromViewController = fromViewController;
  }
  return self;
}

- (instancetype)initWithAVAsset:(AVAsset*)avasset
             fromViewController:(BaseViewController*)fromViewController {
  LC_CHECK_NOT_NULL(avasset);
  LC_CHECK_NOT_NULL(fromViewController);
  if (self = [super init]) {
    LcVideoPlayer* player = [LcVideoPlayer videoPLayerWithAsset:avasset onScreen:nil];
    self->_videoPlayer = player;
    self.fromViewController = fromViewController;
  }
  return self;
}

- (void)viewDidLoad {
  [super viewDidLoad];
  [self setTransparentNavigationBar];
  self.view.backgroundColor = LC_COLOR_DARK;
  self.fromIsHidingNavBar = self.fromViewController.navigationController.isNavigationBarHidden;
  [self setNeedsStatusBarAppearanceUpdate];
  [self disableInteractivePop:YES];
  AVAudioSession* audioSession = [AVAudioSession sharedInstance];
  [audioSession setCategory:AVAudioSessionCategoryPlayback
                withOptions:AVAudioSessionCategoryOptionDuckOthers
                      error:nil];

  self.progressSlider.delegate = self;
  self.bottomControlBar.userInteractionEnabled = NO;
  if (self.navigationController) {
    self.navigationController.modalPresentationCapturesStatusBarAppearance = YES;
  } else {
    self.modalPresentationCapturesStatusBarAppearance = YES;
  }
  if (self.videoPlayer == nil) {
    [self initVideoPlayer];
  }
  [self configVideoPlayer];
  [self refreshControlBar];
  [self addObservers];
  [self rotateToOrientation:UIInterfaceOrientationPortrait];
}

- (void)initVideoPlayer {
  LC_CHECK_TRUE(self.videoPlayer == nil);
  NSURL* url = nil;
  if (self.videoUrl != nil) {
    url = self.videoUrl;
    [self showLoadingIndicator];
  }
  self.videoPlayer = [LcVideoPlayer videoPLayerWithUrl:url extension:@"" onScreen:nil];
}

- (void)configVideoPlayer {
  self.videoPlayer.muted = NO;
  self.videoPlayer.replayWhenFinish = NO;
  self.videoPlayer.playWhenReady = YES;
  self.videoPlayer.screen = self.videoContainerView;
}

- (void)viewSafeAreaInsetsDidChange {
  [super viewSafeAreaInsetsDidChange];
  self.bottomBarBottomConstraint.constant = self.view.safeAreaInsets.bottom;
}

- (void)viewDidLayoutSubviews {
  [super viewDidLayoutSubviews];
  [self.videoPlayer resizeFrame];
  [self refreshOritationButton];
}

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  if (!self.fromIsHidingNavBar) {
    [self.navigationController setNavigationBarHidden:YES animated:animated];
  }
  if (self.isUIPlaying) {
    [self.videoPlayer play];
  }
}

- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  if (!self.fromIsHidingNavBar) {
    [self.navigationController setNavigationBarHidden:NO animated:animated];
  }
  if (self.isUIPlaying) {
    [self.videoPlayer pause];
  }
}

- (void)viewDidDisappear:(BOOL)animated {
  [super viewDidDisappear:animated];
  [[AVAudioSession sharedInstance] setActive:NO
                                 withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}

- (BOOL)prefersStatusBarHidden {
  return YES;
}

- (void)addObservers {
  LcWeakSelf;
  [self.videoPlayer setStateChangedCallback:^(VideoPlayerState newState) {
    LcStrongSelf;
    if (newState == VideoPlayerStateFailed) {
      return;
    }
    [self hideLoadingIndicator];
    if (newState == VideoPlayerStateFinished) {
      [self videoDidFinishPlaying];
    } else {
      if (newState == VideoPlayerStateReady) {
        [self videoReadyForPlaying];
      }
      [self refreshControlBar];
      [self restartTimerForHiddenControlUI];
    }
  }];
  [self.videoPlayer setTimeChangedCallback:^(double currentSeconds) {
    LcStrongSelf;
    [self avPlayerTimeChangesCallBack];
  }];
  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(orientationChange:)
                                               name:UIDeviceOrientationDidChangeNotification
                                             object:nil];
}

- (void)dealloc {
  [self removeObservers];
}

- (void)removeObservers {
  [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)orientationChange:(NSNotification*)notification {
  UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
  switch (orientation) {
    case UIDeviceOrientationPortrait:
    case UIDeviceOrientationPortraitUpsideDown:
      self.closeBtnBottomConstraint.constant = 12.0;
      break;
    case UIDeviceOrientationLandscapeLeft:
    case UIDeviceOrientationLandscapeRight:
      self.closeBtnBottomConstraint.constant = 0.0;
      break;
    default:
      break;
  }
}

- (void)videoDidFinishPlaying {
  [self refreshPlayButtonIcon];
  [self hiddenOrShowControlUI];
  [self.class cancelPreviousPerformRequestsWithTarget:self
                                             selector:@selector(hiddenOrShowControlUI)
                                               object:nil];
}

- (void)videoReadyForPlaying {

}

- (void)setCurrentSeconds:(double)currentSeconds {
  self.videoPlayer.currentSeconds = currentSeconds;
}

- (double)getCurrentSeconds {
  return self.videoPlayer.currentSeconds;
}

- (double)getTotalSeconds {
  return self.videoPlayer.totalSeconds;
}

- (void)avPlayerTimeChangesCallBack {
  if (!self.progressSlider.isTouching) {
    [self refreshTimeUI];
  }
}

- (void)previewEndPause {
  self.isPreviewEndPlay = YES;
  [self.videoPlayer pause];
  [self refreshPlayButtonIcon];
  [self hiddenOrShowControlUI];
  [self.class cancelPreviousPerformRequestsWithTarget:self
                                             selector:@selector(hiddenOrShowControlUI)
                                               object:nil];
}

- (BOOL)isPlayerPlaying {
  return self.videoPlayer.state != VideoPlayerStateUnknow &&
         self.videoPlayer.state != VideoPlayerStateFailed;
}

- (LcVideoPlayer *)originalVideoPlayer {
  return self.videoPlayer;
}

#pragma mark - Additional

- (void)closePage {
  if (self.videoPlayerClosedHandler != nil) {
    self.videoPlayerClosedHandler();
  }
  [self removeObservers];
  self.videoPlayer.stateChangedCallback = nil;
  self.videoPlayer.timeChangedCallback = nil;
  self.videoPlayer.timeControlStatusChangedCallback = nil;
  if (!self.videoPlayerCreatedOutside) {
    [self.videoPlayer free];
  } else {
    self.videoPlayer.muted = YES;
    [self.videoPlayer pause];
  }
  if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)] &&
      [[UIApplication sharedApplication] statusBarOrientation] != UIDeviceOrientationPortrait) {
    [self rotateToOrientation:UIInterfaceOrientationPortrait];
  }
  [self navigationBack];
}

- (void)pause {
  [self.videoPlayer pause];
  [self refreshPlayButtonIcon];
  self.playButton.selected = YES;
}
- (void)play {
  [self.videoPlayer play];
  [self refreshPlayButtonIcon];
  self.playButton.selected = NO;
}

#pragma mark - refresher
- (void)refreshControlBar {
  if (self.videoPlayer.state == VideoPlayerStateUnknow ||
      self.videoPlayer.state == VideoPlayerStateFailed) {
    return;
  }
  self.bottomControlBar.userInteractionEnabled = YES;
  [self.progressSlider clearMaxDragValue];
  self.voiceButton.selected = self.videoPlayer.muted;
  [self refreshTimeUI];
  [self refreshPlayButtonIcon];
}

- (void)refreshTimeUI {
  if (self.videoPlayer.totalSeconds == 0) {
    return;
  }
  NSString* formatString = @"mm:ss";
  self.totalTimeLabel.text = [[NSDate dateWithTimeIntervalSince1970:self.videoPlayer.totalSeconds]
      toStringWithFormat:formatString];
  self.currentTimeLabel.text =
      [[NSDate dateWithTimeIntervalSince1970:self.videoPlayer.currentSeconds]
          toStringWithFormat:formatString];
  if (self.videoPlayer.totalSeconds != 0 && !self.progressSlider.isTouching) {
    self.progressSlider.value = self.videoPlayer.currentSeconds / self.videoPlayer.totalSeconds;
  }

  // cache size indicator
  NSArray* loadedTimeRanges = [self.videoPlayer loadedTimeRanges];
  if (loadedTimeRanges.count != 0) {
    CMTimeRange timeRange = [loadedTimeRanges[0] CMTimeRangeValue];
    Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
    Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
    double result = startSeconds + durationSeconds;
    if (self.videoPlayer.totalSeconds != 0) {
      self.progressSlider.cachePercentage = result / self.videoPlayer.totalSeconds;
    }
  }
}

- (void)refreshPlayButtonIcon {
  if (self.isPreviewEndPlay || self.videoPlayer.state == VideoPlayerStateUnknow ||
      self.videoPlayer.state == VideoPlayerStateFailed) {
  } else {
    if (self.videoPlayer.state == VideoPlayerStateFinished) {
      NSString* replayImage = @"g_replay_48x48";
      [self.playButton setImage:[UIImage imageNamed:replayImage]
                       forState:UIControlStateNormal];
      [self.playButton setImage:[UIImage imageNamed:replayImage]
                       forState:UIControlStateSelected];
    } else {
      NSString* pauseImage = @"g_pause_48x48";
      NSString* playImage = @"g_play_48x48";
      [self.playButton setImage:[UIImage imageNamed:pauseImage]
                       forState:UIControlStateNormal];
      [self.playButton setImage:[UIImage imageNamed:playImage]
                       forState:UIControlStateSelected];
    }
  }
}

- (void)refreshOritationButton {
  if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationUnknown ||
      [[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait ||
      [[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortraitUpsideDown) {
    self.rotatoButton.selected = NO;
  } else {
    self.rotatoButton.selected = YES;
  }
}

#pragma mark - IBActions

- (IBAction)swipeGestureRecognized:(id)sender {
  [self closeButtonClicked:nil];
}

- (IBAction)closeButtonClicked:(id)sender {
  [self closePage];
}

- (IBAction)playButtonClicked:(id)sender {
  if (self.isPreviewEndPlay) {
    return;
  } else if (self.videoPlayer.state == VideoPlayerStateFinished) {
    [self seekToBeginTime];
    self.playButton.selected = NO;
  } else {
    self.playButton.selected = !self.playButton.selected;
  }
  if (!self.isUIPlaying) {
    [self.videoPlayer pause];
  } else {
    [self.videoPlayer play];
  }
  [self restartTimerForHiddenControlUI];
}

- (IBAction)voiceButtonClicked:(id)sender {
  [self restartTimerForHiddenControlUI];
  self.voiceButton.selected = !self.voiceButton.selected;
  self.videoPlayer.muted = self.voiceButton.selected;
}

- (IBAction)rotatoButtonClicked:(id)sender {
  [self restartTimerForHiddenControlUI];
  UIInterfaceOrientation orientation = 0;
  if (self.rotatoButton.selected) {
    orientation = UIInterfaceOrientationPortrait;
  } else {
    orientation = UIInterfaceOrientationLandscapeLeft;
  }
  [self rotateToOrientation:orientation];
}

- (void)seekToBeginTime {
  self.currentSeconds = 0;
}

- (IBAction)onBackGoundClicked:(id)sender {
  [self hiddenOrShowControlUI];
  [self restartTimerForHiddenControlUI];
}

- (void)restartTimerForHiddenControlUI {
  [self.class cancelPreviousPerformRequestsWithTarget:self
                                             selector:@selector(hiddenOrShowControlUI)
                                               object:nil];
  if (!self.bottomControlBar.hidden && !self.progressSlider.isTouching) {
    [self performSelector:@selector(hiddenOrShowControlUI) withObject:nil afterDelay:3];
  }
}

- (void)hiddenOrShowControlUI {
  BOOL goHidden = !self.bottomControlBar.hidden;
  if (self.isPreviewEndPlay || self.videoPlayer.state == VideoPlayerStateFinished) {
    goHidden = NO;
  }
  self.topGuideBackgroundView.hidden = goHidden;
  self.bottomControlBar.hidden = goHidden;
  self.playButton.hidden = YES;
}

- (void)navigationBack {
  [self hideLoadingIndicator];
  CATransition* transition = [CATransition animation];
  transition.duration = 0.25;
  transition.timingFunction =
      [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
  transition.type = kCATransitionFade;
  [self.navigationController.view.layer addAnimation:transition forKey:nil];
  [self.navigationController popViewControllerAnimated:NO];
}

#pragma mark - rotation
- (BOOL)shouldAutorotate {
  return YES;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskAll;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
  return UIInterfaceOrientationLandscapeLeft;
}

- (void)didProgressSliderValueChanged:(VideoProgressSlider*)progressSlider {
  if (self.isPreviewEndPlay) {
    self.isPreviewEndPlay = NO;
    [self refreshPlayButtonIcon];
  } else if (self.videoPlayer.state == VideoPlayerStateFinished) {
    [self refreshPlayButtonIcon];
  }
  self.currentSeconds = self.videoPlayer.totalSeconds * self.progressSlider.value;
  [self restartTimerForHiddenControlUI];
  [self refreshTimeUI];
  self.playButton.selected = NO;
  if (self.progressSlider.isTouching) {
    [self.videoPlayer pause];
  } else {
    [self.videoPlayer play];
  }
}

- (void)cancel {
  [self dismissViewControllerAnimated:YES
                           completion:^{
                             if (self.videoPlayerClosedHandler != nil) {
                               self.videoPlayerClosedHandler();
                             }
                           }];
}

- (void)applicationDidEnterBackground {
  [super applicationDidEnterBackground];
  if (self.videoPlayer.state != VideoPlayerStateFinished) {
    [self.videoPlayer pause];
  }
}

- (void)applicationWillEnterForeground {
  [super applicationWillEnterForeground];
  if (self.isUIPlaying && self.videoPlayer.state != VideoPlayerStateFinished) {
    [self.videoPlayer play];
  }
}

- (void)rotateToOrientation:(UIInterfaceOrientation)orientation {
  SEL selector = NSSelectorFromString(@"setOrientation:");
  NSInvocation* invocation = [NSInvocation
      invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
  [invocation setSelector:selector];
  [invocation setTarget:[UIDevice currentDevice]];
  int val = (int)orientation;
  [invocation setArgument:&val atIndex:2];
  [invocation invoke];
}

- (void)setPlayButtonHidden:(BOOL)hidden {
  self.playButton.hidden = hidden;
}

- (void)setPlayerBottomActionHidden:(BOOL)hidden {
  self.playerBottomActionContainerConstraint.constant = hidden ? 0.0 : 75.0;
}

@end
